﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using System.IO;
using System.Drawing;
using Microsoft.Xna.Framework.Graphics;

namespace Assignment_2
{
    public class SphereStuff
    {
        #region variables
        private HSL[,] HSLColours;
        private int stacks, slices;

        public int Height { get; private set; }
        public int Width { get; private set; }
        public float minWaterSize { get; set; }
        #endregion

        /// <summary>
        /// The constructor.
        /// </summary>
        public SphereStuff()
        {
            minWaterSize = 1;
            stacks = 100;
            slices = 100;
        }

        /// <summary>
        /// This function converts RBG colour to HSL.
        /// </summary>
        /// <param name="c1">The RGB colour to convert.</param>
        /// <returns>The colour in HSL format.</returns>
        private HSL RGB2HSL(Microsoft.Xna.Framework.Color c1)
        {
            double themin, themax, delta;
            HSL c2;

            themin = Math.Min(c1.R, Math.Min(c1.G, c1.B));
            themax = Math.Max(c1.R, Math.Max(c1.G, c1.B));
            delta = themax - themin;
            c2.l = (themin + themax) / 2;
            c2.s = 0;
            if (c2.l > 0 && c2.l < 1)
                c2.s = delta / (c2.l < 0.5 ? (2 * c2.l) : (2 - 2 * c2.l));
            c2.h = 0;
            if (delta > 0)
            {
                if (themax == c1.R && themax != c1.G)
                    c2.h += (c1.G - c1.B) / delta;
                if (themax == c1.G && themax != c1.B)
                    c2.h += (2 + (c1.B - c1.R) / delta);
                if (themax == c1.B && themax != c1.R)
                    c2.h += (4 + (c1.R - c1.G) / delta);
                c2.h *= 60;
            }
            return (c2);
        }

        /// <summary>
        /// This function converts a texture to colour array.
        /// </summary>
        /// <param name="texture">The texture to convert.</param>
        public void TextureTo2DArray(Texture2D texture)
        {            
            Width = texture.Width;
            Height = texture.Height;
            HSLColours = new HSL[Width, Height];

            Microsoft.Xna.Framework.Color[] colors1D = new Microsoft.Xna.Framework.Color[Width * Height];
            texture.GetData(colors1D);

            Microsoft.Xna.Framework.Color[,] colors2D = new Microsoft.Xna.Framework.Color[Width, Height];
            for (int x = 0; x < texture.Width; x++)
                for (int y = 0; y < texture.Height; y++)
                {
                    HSLColours[x, y] = RGB2HSL(colors1D[x + y * texture.Width]);
                    if (HSLColours[x, y].h < 1)
                        minWaterSize = (float)HSLColours[x, y].h;
                }
        }

        /// <summary>
        /// This function calculates the Z value for each "pixel".
        /// </summary>
        /// <param name="x">The X position.</param>
        /// <param name="y">The Y position.</param>
        /// <returns>THe calculated Z value.</returns>
        public float CalculateZ(float x, float y)
        {
            // Minus otherwise the mountains will be inverted.
            return -(float)HSLColours[(int)((Width-1)*x), (int)((Height-1)*y)].h / 3600;
        }

        public Vector3 getSphereCoords(Vector3 planarCoords)
        {
            Vector3 sphereCoords = new Vector3();

            sphereCoords.X = (planarCoords.Z + CalculateZ(planarCoords.X / (float)slices, planarCoords.Y / (float)stacks)) * (float)Math.Cos(MathHelper.PiOver2 - planarCoords.Y * (MathHelper.Pi / stacks)) * (float)Math.Sin(planarCoords.X * MathHelper.TwoPi / slices); 
            sphereCoords.Y = (planarCoords.Z + CalculateZ(planarCoords.X / (float)slices, planarCoords.Y / (float)stacks)) * (float)Math.Sin(MathHelper.PiOver2 - planarCoords.Y * (MathHelper.Pi / stacks));
            sphereCoords.Z = - (planarCoords.Z + CalculateZ(planarCoords.X / (float)slices, planarCoords.Y / (float)stacks)) * (float)Math.Cos(MathHelper.PiOver2 - planarCoords.Y * (MathHelper.Pi / stacks)) * (float)Math.Cos(planarCoords.X * MathHelper.TwoPi / slices);

            return sphereCoords;
        }
    }
}
